/*
 * GMMInitMapper.h
 *
 *  Created on: 2011-8-17
 *      Author: yong
 */

#ifndef GMMINITMAPPER_H_
#define GMMINITMAPPER_H_
#include<iostream>
#include <boost/random.hpp>
#include <boost/shared_ptr.hpp>
#include "Typedef.h"
#include "Page.h"
#include "Config.h"
#include "Util.h"
namespace distrim
{
template<typename K, typename V1, typename V2>
class GMMInitMapper: public Mapper<K, V1, std::vector<
		boost::numeric::ublas::matrix<V2> > >
{
private:
	typedef boost::numeric::ublas::matrix<V2> Matrix;
	typedef boost::variate_generator<boost::minstd_rand&, boost::uniform_int<> >
			RIG;
	typedef boost::uniform_int<> BUI;
	typedef boost::minstd_rand BMR;
	typedef std::vector<Matrix> MV;

public:
	GMMInitMapper(KeyValuePage<K, V1, MV> *ptrKeyValuePage,
			const Config &config, MV *ptrParam) :
		Mapper<K, V1, MV> (ptrKeyValuePage, config, ptrParam), m_clusterNum(
				config.GetClusterNum()), m_vecPartialSum(3
				* config.GetClusterNum() + 1), m_valueElemCount(
				config.GetValueElemCount()), m_tV(1, m_valueElemCount), m_tA(
				m_valueElemCount, m_valueElemCount), m_gen(
				static_cast<size_t> (std::time(0))), m_dist(1, m_clusterNum),
				m_rig(m_gen, m_dist)
	{
		setup();
	}

	virtual ~GMMInitMapper()
	{
	}

	virtual void Map(const KeyValue<K, V1> &keyValue)
	{
		int randomLabel = m_rig();
		m_vecPartialSum[randomLabel](0, 0) += 1.0f;
		Util::KeyValueToMatrix(keyValue, m_tV);
		m_vecPartialSum[randomLabel + m_clusterNum] += m_tV;
		prod(trans(m_tV), m_tV, m_tA);
		m_vecPartialSum[randomLabel + 2 * m_clusterNum] += m_tA;
	}

	inline const MV &GetPartialSum() const
	{
		return m_vecPartialSum;
	}

	inline void Reset()
	{
		m_vecPartialSum[0](0, 0) = -1 * std::numeric_limits<V2>::max() / (2
				* Mapper<K, V1, MV>::GetConfig().GetTotalPoints()); // Reset likelihood.
		for (size_t c = 1; c < m_clusterNum + 1; ++c)
		{
			m_vecPartialSum[c].clear();
			m_vecPartialSum[c + m_clusterNum].clear();
			m_vecPartialSum[c + 2 * m_clusterNum].clear();
		}
	}

private:
	virtual void setup()
	{
		m_vecPartialSum[0] = Matrix(1, 1, -1 * std::numeric_limits<V2>::max()
				/ (2 * Mapper<K, V1, MV>::GetConfig().GetTotalPoints()));
		for (size_t c = 1; c < m_clusterNum + 1; ++c)
		{
			m_vecPartialSum[c] = Matrix(1, 1, V2()); // gamma
			m_vecPartialSum[c + m_clusterNum] = Matrix(1, m_valueElemCount,
					V2()); // mean
			m_vecPartialSum[c + 2 * m_clusterNum] = Matrix(m_valueElemCount,
					m_valueElemCount, V2()); // x^T * x
		}
	}

private:
	size_t m_clusterNum;
	MV m_vecPartialSum;
	size_t m_valueElemCount;
	Matrix m_tV;
	Matrix m_tA;
	BMR m_gen;
	BUI m_dist;
	RIG m_rig;

};

}

#endif /* GMMINITMAPPER_H_ */
